#include "StdAfx.h"
#include "CardSet.h"

using namespace SHGame;

/*
Creates a new, empty, CardSet
*/
CardSet::CardSet(void) {
	this->cards = gcnew LinkedList<Card^>();
}

/*
Adds a new card to this set in the next empty spot.
The internal array is expanded if necessary.
Returns true if the card was added (the card may not have been
added if it was already present in this set).
*/
bool CardSet::add(Card ^card) {
	if (this->contains(card)) {
		return false;
	}
	this->cards->AddLast(card);
	this->sort();
	return true;
}


/*
Removes the given card from this set
shifts over the elements in the array to fill the gap.
returns true if the card was removed (meaning that the
card was actually in this set).
*/
bool CardSet::remove(Card ^card) {
	if ( this->contains(card) ) {
		this->cards->Remove(card);
		return true;
	}
	return false;
}

/*
checks if the given card is contained in this set
returns true if the given card is contained.
*/
bool CardSet::contains(Card ^card) {
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	while ( enumer->MoveNext() ) {
		if (enumer->Current->Equals(card))
			return true;
	}
	return false;
}

/*
checks if this set contains a trump card.
returns true if there is a trump card in this set.
*/
bool CardSet::hasTrump() {
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	while ( enumer->MoveNext() ) {
		Card ^ temp = enumer->Current;
		if (temp->isTrump()) {
			return true;
		}
	}
	return false;
}

Card^ CardSet::get(int i) {
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	Card ^ temp;
	if (i < 0) 
		return nullptr;
	while ( enumer->MoveNext() ) {
		temp = enumer->Current;
		if (i <= 0)
			return temp;
		i--;
	}
	return nullptr;

}

LinkedList<Card^>^ CardSet::followSuit(Card^ c) {
	LinkedList<Card^> ^list = gcnew LinkedList<Card^>();
	if (! canFollowSuit(c) ) {
		return this->cards;
	}
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	while ( enumer->MoveNext() ) {
		Card ^ temp = enumer->Current;
		if (temp->onSuit(c)) {
			list->AddFirst(temp);
		}
	}
	return list;
}

bool CardSet::canFollowSuit(Card^ card)
{
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	while ( enumer->MoveNext() ) {
		Card ^ temp = enumer->Current;
		if (temp->onSuit(card)) {
			return true;
		}
	}
	return false;
}

int CardSet::Size() {
	return this->cards->Count;
}

void CardSet::sort() {
	LinkedList<Card^> ^temp = gcnew LinkedList<Card^>();
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	while (enumer->MoveNext()) {
		if (temp->Count == 0) {
			temp->AddFirst(enumer->Current);
			continue;
		}
		IEnumerator<Card^> ^tempe = temp->GetEnumerator();
		Card^ c = enumer->Current;
		Card ^smaller;
		while (tempe->MoveNext()) {
			if (tempe->Current->getRank() < c->getRank()) {
				smaller = tempe->Current;
				break;
			}
		}
		if (smaller == nullptr) {
			temp->AddLast(c);
		} else {
			temp->AddBefore(temp->Find(smaller), c);
		}
	}
	this->cards = temp;
}

int CardSet::GetFailSuits() 
{
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	array<int>^ arr = {0,0,0,0};
	while (enumer->MoveNext()) 
	{
		// skip trump, we're counting fail
		if (enumer->Current->isTrump())
			continue;
		// add to the array index
		arr[Card::findIndex(Card::SUITS, enumer->Current->getSuit())]++;
	}
	int fails = 0;
	if (arr[0] > 0) fails++;
	if (arr[1] > 0) fails++;
	if (arr[2] > 0) fails++;
	return fails;
}

int CardSet::GetStrength()
{
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	int pow = 0;
	while (enumer->MoveNext()) 
	{
		pow += enumer->Current->GetPickRating();
	}
	double fact =  2 / (double) (this->GetFailSuits() + 1);
	if (this->contains(Card::JackOfDiamonds))
		pow = (int) pow * 0.6;
	//fact = fact / 2;
	if (fact == 0)
		return (int) pow;
	return (int)(pow * fact);
}
Card^ CardSet::GetLongFail()
{
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	array<int>^ arr = {0,0,0,0};
	while (enumer->MoveNext()) 
	{
		// skip trump, we're counting fail
		if (enumer->Current->isTrump())
			continue;
		// add to the array index
		arr[Card::findIndex(Card::SUITS, enumer->Current->getSuit())]++;
	}
	Card::Suit suit;
	if (arr[0] >= arr[1] && arr[0] >= arr[2])
		suit = Card::Suit::Clubs;
	if (arr[1] >= arr[0] && arr[1] >= arr[2])
		suit = Card::Suit::Spades;
	if (arr[2] >= arr[1] && arr[2] >= arr[0])
		suit = Card::Suit::Hearts;
	if (! this->canFollowSuit(gcnew Card(suit, Card::Face::Seven)))
		return GetACard();
	return this->followSuit(gcnew Card(suit, Card::Face::Seven))->First->Value;
}

Card^ CardSet::GetACard() {
	return this->cards->First->Value;
}

Card^ CardSet::GetShortFail()
{
	IEnumerator<Card^> ^enumer = this->cards->GetEnumerator();
	array<int>^ arr = {0,0,0,0};
	while (enumer->MoveNext()) 
	{
		// skip trump, we're counting fail
		if (enumer->Current->isTrump())
			continue;
		// add to the array index
		arr[Card::findIndex(Card::SUITS, enumer->Current->getSuit())]++;
	}
	Card::Suit suit;
	if (arr[0] == 0) arr[0] = 9;
	if (arr[1] == 0) arr[1] = 9;
	if (arr[2] == 0) arr[2] = 9;
	if (arr[0] <= arr[1] && arr[0] <= arr[2])
		suit = Card::Suit::Clubs;
	if (arr[1] <= arr[0] && arr[1] <= arr[2])
		suit = Card::Suit::Spades;
	if (arr[2] <= arr[1] && arr[2] <= arr[0])
		suit = Card::Suit::Hearts;
	if (! this->canFollowSuit(gcnew Card(suit, Card::Face::Seven)))
		return GetACard();
	return this->followSuit(gcnew Card(suit, Card::Face::Seven))->First->Value;
	
}
Card^ CardSet::GetATrump()
{
	if (this->canFollowSuit(Card::JackOfDiamonds))
		return this->followSuit(Card::JackOfDiamonds)->First->Value;
	// return a random card...
	return this->GetShortFail();
}